package concurrency

import (
	"context"
	"fmt"
	"sync"
	"time"
)

// 无法发送停止指令停止协程
func main01() {
	var wg sync.WaitGroup
	wg.Add(1)
	go func() {
		defer wg.Done()
		watchDog01("[dog01]")
	}()
	wg.Wait()
}

func watchDog01(name string) {
	// for select 循环 一直监控
	for {
		select {
		default:
			fmt.Println(name, "正在监控...")
		}
		time.Sleep(1 * time.Second)
	}
}

// 监控5s发送停止指令
func main02() {
	var wg sync.WaitGroup
	wg.Add(1)
	stopWatch := make(chan bool) //停止监控命令的全局变量

	go func() {
		defer wg.Done()
		watchDog02(stopWatch, "[watchdog02]")
	}()
	// 监控5秒
	time.Sleep(5 * time.Second)
	//停止指令
	stopWatch <- true
	wg.Wait()
}

// 通过chan 发送指令停止协程
func watchDog02(stopWatch chan bool, name string) {
	for {
		select {
		case <-stopWatch:
			fmt.Println("停止监控...")
			return
		default:
			fmt.Println(name, "正在监控...")
		}
		time.Sleep(1 * time.Second)
	}
}

func mainContext() {
	var wg sync.WaitGroup
	wg.Add(1)
	ctx, stop := context.WithCancel(context.Background())
	go func() {
		defer wg.Done()
		watchDogContext(ctx, "[watchdog]")
	}()

	time.Sleep(5 * time.Second) //让监控狗监控5s
	stop()                      //发送停止指令
	wg.Wait()

}

//使用context做监控
func watchDogContext(ctx context.Context, name string) {
	// 开启 for select 循环，一直后台监控
	for {
		select {
		case <-ctx.Done():
			fmt.Println(name, "停止指令已收到，马上停止")
			return
		default:
			fmt.Println(name, "正在监控...")
		}
		time.Sleep(1 * time.Second)
	}
}

// context 控制多个goroutine
func mainContextMulti() {
	ctx, cancel := context.WithCancel(context.Background())
	go watchDogContext(ctx, "[watchdog1]")
	go watchDogContext(ctx, "[watchdog2]")
	go watchDogContext(ctx, "[watchdog3]")

	time.Sleep(5 * time.Second)
	fmt.Println("停止监控")
	cancel()
	//为了检测监控过是否停止，如果没有监控输出，就表示停止了
	time.Sleep(3 * time.Second)
}

var key string = "name"

func watchContext(ctx context.Context) {
	for {
		select {
		case <-ctx.Done():
			fmt.Println(ctx.Value(key), "监控退出，停止")
			return
		default:
			//取值
			fmt.Println(ctx.Value(key), "goroutine watching...")
			time.Sleep(2 * time.Second)
		}
	}
}

// context Value
func mainContextValue() {
	ctx, cancel := context.WithCancel(context.Background())

	//附加值
	valueCtx := context.WithValue(ctx, key, "[watchdog1]")
	go watchContext(valueCtx)
	time.Sleep(5 * time.Second)
	fmt.Println("可以了，通知监控停止")
	cancel()
	//为了检测监控过是否停止，如果没有监控输出，就表示停止了
	time.Sleep(3 * time.Second)
}
